package lazyj;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * @author Costin Grigoras
 * {@link http://lazyj.sourceforge.net/download/lazyj.jar}
 *
 */
public class Util {
	/**
	 * HTML special characters to base characters mapping
	 */
	private static final HashMap<String, String> HTML_CHAR_MAP = new HashMap<String, String>(64, 0.95f);
	
	static{
		// upper case HTML special characters
		HTML_CHAR_MAP.put("Aacute", "A");
		HTML_CHAR_MAP.put("Agrave", "A");
		HTML_CHAR_MAP.put("Acirc", "A");
		HTML_CHAR_MAP.put("Atilde", "A");
		HTML_CHAR_MAP.put("Aring", "A");
		HTML_CHAR_MAP.put("Auml", "A");
		HTML_CHAR_MAP.put("AElig", "AE");
		HTML_CHAR_MAP.put("Ccedil", "C");
		HTML_CHAR_MAP.put("Eacute", "E");
		HTML_CHAR_MAP.put("Egrave", "E");
		HTML_CHAR_MAP.put("Ecirc", "E");
		HTML_CHAR_MAP.put("Euml", "E");
		HTML_CHAR_MAP.put("Iacute", "I");
		HTML_CHAR_MAP.put("Igrave", "I");
		HTML_CHAR_MAP.put("Icirc", "I");
		HTML_CHAR_MAP.put("Iuml", "I");
		HTML_CHAR_MAP.put("Ntilde", "N");
		HTML_CHAR_MAP.put("Oacute", "O");
		HTML_CHAR_MAP.put("Ograve", "O");
		HTML_CHAR_MAP.put("Ocirc", "O");
		HTML_CHAR_MAP.put("Otilde", "O");
		HTML_CHAR_MAP.put("Ouml", "O");
		HTML_CHAR_MAP.put("Oslash", "O");
		HTML_CHAR_MAP.put("Uacute", "U");
		HTML_CHAR_MAP.put("Ugrave", "U");
		HTML_CHAR_MAP.put("Ucirc", "U");
		HTML_CHAR_MAP.put("Uuml", "U");
		HTML_CHAR_MAP.put("Yacute", "Y");

		// lower case HTML special characters
		HTML_CHAR_MAP.put("aacute", "a");
		HTML_CHAR_MAP.put("agrave", "a");
		HTML_CHAR_MAP.put("acirc", "a");
		HTML_CHAR_MAP.put("atilde", "a");
		HTML_CHAR_MAP.put("auml", "a");
		HTML_CHAR_MAP.put("aelig", "ae");
		HTML_CHAR_MAP.put("ccedil", "c");
		HTML_CHAR_MAP.put("eacute", "e");
		HTML_CHAR_MAP.put("egrave", "e");
		HTML_CHAR_MAP.put("ecirc", "e");
		HTML_CHAR_MAP.put("euml", "e");
		HTML_CHAR_MAP.put("iacute", "i");
		HTML_CHAR_MAP.put("igrave", "i");
		HTML_CHAR_MAP.put("icirc", "i");
		HTML_CHAR_MAP.put("iuml", "i");
		HTML_CHAR_MAP.put("ntilde", "n");
		HTML_CHAR_MAP.put("oacute", "o");
		HTML_CHAR_MAP.put("ograve", "o");
		HTML_CHAR_MAP.put("ocirc", "o");
		HTML_CHAR_MAP.put("otilde", "o");
		HTML_CHAR_MAP.put("ouml", "o");
		HTML_CHAR_MAP.put("oslash", "o");
		HTML_CHAR_MAP.put("uacute", "u");
		HTML_CHAR_MAP.put("ugrave", "u");
		HTML_CHAR_MAP.put("ucirc", "u");
		HTML_CHAR_MAP.put("uuml", "u");
		HTML_CHAR_MAP.put("yacute", "y");
		HTML_CHAR_MAP.put("yuml", "y");
		HTML_CHAR_MAP.put("#160", " ");
	}
	
	/**
	 * HTML comments
	 */
	private static final Pattern PATTERN_HTML_COMMENT = Pattern.compile("<!--.*?-->", Pattern.DOTALL);
	
	/**
	 * JavaScript tags
	 */
	private static final Pattern PATTERN_HTML_SCRIPT = Pattern.compile("<script.*?</script.*?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * Style tags
	 */
	private static final Pattern PATTERN_HTML_STYLE = Pattern.compile("<style.*?</style.*?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * HTML Head element
	 */
	private static final Pattern PATTERN_HTML_HEAD = Pattern.compile("<head.*?</head.*?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * Many spaces as one
	 */
	private static final Pattern PATTERN_HTML_SPACES = Pattern.compile("\\s+", Pattern.DOTALL);
	
	/**
	 * What counts as new line
	 */
	private static final Pattern PATTERN_HTML_BR = Pattern.compile("<(ul|br|/li|/option|/div|table|/tr).*?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * Any HTML tag
	 */
	private static final Pattern PATTERN_HTML_TAG = Pattern.compile("<.*?>", Pattern.DOTALL);
	
	/**
	 * What to put as bullets
	 */
	private static final Pattern PATTERN_HTML_BULL = Pattern.compile("<(li|option).*?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * Special HTML characters 
	 */
	private static final Pattern PATTERN_HTML_SPECIAL = Pattern.compile("&[a-zA-Z]{2,6};", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
	
	/**
	 * New lines, possibly surrounded by spaces
	 */
	private static final Pattern PATTERN_HTML_LINES = Pattern.compile("\\s*\n\\s*"); 
	
	/**
	 * Left and right trim
	 */
	private static final Pattern PATTERN_HTML_TRIM = Pattern.compile("(^\\s+)|(\\s+$)");
	
	/**
	 * Simple convertor from HTML to plain text. Can be used for example to automatically add a plain text email body part when
	 * all you have is the HTML input.
	 * 
	 * @param sHTML HTML input
	 * @return plain text version of the HTML
	 * @since 1.0.5
	 */
	public static String htmlToText(final String sHTML){
		return htmlToText(sHTML, 0);
	}
	
	/**
	 * Don't collapse multiple blank characters in a single space.
	 */
	public static final int HTML_OPTION_KEEP_SPACES = 1;
	
	/**
	 * Don't collapse multiple new lines in a single new line
	 */
	public static final int HTML_OPTION_KEEP_NEWLINES = 2;
	
	/**
	 * Simple convertor from HTML to plain text. Can be used for example to automatically add a plain text email body part when
	 * all you have is the HTML input.
	 * 
	 * @param sHTML HTML input
	 * @param options a binary OR between any Utils.HTML_OPTION_* constants
	 * @return plain text version of the HTML
	 */
	public static String htmlToText(final String sHTML, final int options){
		// first, remove all the comments
		
		Matcher m = PATTERN_HTML_COMMENT.matcher(sHTML);
		String s = m.replaceAll("");
		
		m = PATTERN_HTML_SCRIPT.matcher(s);
		s = m.replaceAll("");
		
		m = PATTERN_HTML_STYLE.matcher(s);
		s = m.replaceAll("");
	
		m = PATTERN_HTML_HEAD.matcher(s);
		s = m.replaceAll("");
	
		if ( (options & HTML_OPTION_KEEP_SPACES) == 0){
			m = PATTERN_HTML_SPACES.matcher(s);
			s = m.replaceAll(" ");
		}
		
		m = PATTERN_HTML_BR.matcher(s);
		s = m.replaceAll("\n");
		
		m = PATTERN_HTML_BULL.matcher(s);
		s = m.replaceAll("- ");
		
		m = PATTERN_HTML_TAG.matcher(s);
		s = m.replaceAll("");
	
		s = s.replace("&nbsp;", " ");
		s = s.replace("&lt;", "<");
		s = s.replace("&gt;", ">");
		s = s.replace("&raquo;", ">>");
		s = s.replace("&laquo;", "<<");
		s = s.replace("&copy;", "(c)");
		s = s.replace("&amp;", "&");
		s = s.replace("&ndash;", "-");
		s = s.replace("&mdash;", "-");
		s = s.replace("&quot;", "\"");
		s = s.replace("&hellip;", "...");
		s = s.replace("&rsquo;", "'");
		s = s.replace("&lsquo;", "`");
		s = s.replace("&rdquo;", "\"");
		s = s.replace("&ldquo;", "\"");
		
		for (Map.Entry<String, String> me: HTML_CHAR_MAP.entrySet()){
			s = s.replace('&'+me.getKey()+';', me.getValue());
		}
		
		m = PATTERN_HTML_SPECIAL.matcher(s);
		s = m.replaceAll("");
	
		if ( (options & HTML_OPTION_KEEP_NEWLINES) == 0){
			m = PATTERN_HTML_LINES.matcher(s);
			s = m.replaceAll("\n");
		}
	
		m = PATTERN_HTML_TRIM.matcher(s);
		s = m.replaceAll("");		
	
		return s;
	}
}

